package com.xiaoyy.app.extend.integration.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.copier.SrcToDestCopier;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.xiaoyy.app.extend.common.vo.BusTravelUrlVO;
import com.xiaoyy.app.extend.common.vo.BusTravelVcardidVO;
import com.xiaoyy.app.extend.integration.JhxBusTravelIntegration;
import com.xiaoyy.core.common.exception.AppException;
import com.xiaoyy.core.common.vo.AppResponse;
import com.xiaoyy.core.common.vo.BaseVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.*;

@Service
public class JhxBusTravelIntegrationImpl implements JhxBusTravelIntegration {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    private final static String url = "http://m.jinhuaxing.com.cn/jhx";
    private final static String h5Url = "https://www.0579jhx.com/wap/index/talent_card";
    private final static String appkey = "FB5CC7B3F0628F20D8CBB21E85FD27A6";
    private final static String appid = "057101";
    @Value("${system.config.jhrc.app.url}")
    private String jhrcUrl;


    @Override
    public BusTravelUrlVO getUrl(BaseVO vo) {
        String vcardid = getVcardid(vo);
        if(StringUtils.isBlank(vcardid)){
            throw new AppException("获取用户卡号失败");
        }
        Map<String,Object> params = new HashMap<>();
        params.put("vcardid",vcardid);
        getCommonParams(params);
        if(StringUtils.isBlank(appkey)){
            throw new AppException("金华行appkey参数(jhx_app_key)未配置");
        }
        String sign = getSign(params,appkey);
        params.put("sign",sign);
        String urlparams = HttpUtil.toParams(params);
        //jhx_h5_url
        if(StringUtils.isBlank(h5Url)){
            throw new AppException("金华行用户刷码页url(jhx_h5_url)未配置");
        }
        BusTravelUrlVO busTravelUrlVO = new BusTravelUrlVO();
        busTravelUrlVO.setUrl(h5Url+"?"+urlparams);
        return busTravelUrlVO;
    }

    /**
     * 公交出行-获取金华行卡号(需登录)
     * @return
     */
    private String getVcardid(BaseVO vo) {
        BusTravelVcardidVO busTravelVcardidVO = getBusTravelVcardidVO(vo);
        if(StringUtils.isNotBlank(busTravelVcardidVO.getVcardid())){
            if(Objects.nonNull(busTravelVcardidVO.getIsCancel()) && busTravelVcardidVO.getIsCancel()){
                try{
                    cancelAccount(busTravelVcardidVO.getVcardid());
                }catch (Exception e){
                    logger.error("注销卡失败",e);
                }
            }else {
                return busTravelVcardidVO.getVcardid();
            }
        }
        busTravelVcardidVO.setIsCancel(null);
        busTravelVcardidVO.setVcardid(null);
        Map<String,Object> params = BeanUtil.beanToMap(busTravelVcardidVO,true,true);
        Map<String,Object> data = null;
        try{
            data = registerAccount(params);
        }catch (Exception e){
            logger.error("金华行开卡失败",e);
            throw new AppException(e.getMessage());
        }
        if(Objects.nonNull(data)){
            if(data.containsKey("vcardid")){
                busTravelVcardidVO.setVcardid(data.get("vcardid").toString());
            }
            if(data.containsKey("userkey_public")){
                busTravelVcardidVO.setUserkeyPublic(data.get("userkey_public").toString());
            }
            //调用金华人才后端保存卡号
            try{
                busTravelVcardidVO.setAccessToken(vo.getAccessToken());
                saveVcardid(busTravelVcardidVO);
            }catch (Exception e){
                logger.error("保存本地卡信息失败",e);
            }
            return busTravelVcardidVO.getVcardid();
        }
        return null;
    }


    /**
     * 金华行开户
     * @return
     */
    private Map<String,Object> registerAccount(Map<String,Object> params){
        String method = "/ccard/account_reg";
        //生成设置随机数
        String uuid = "";
        do{
            uuid = IdUtil.fastSimpleUUID().replaceAll("-","");
        }while (uuid.length()<16);
        String random = uuid.substring(0,16);
        params.put("random",random);
        //设置公共参数
        getCommonParams(params);
        //获取签名
        String sign = getSign(params,null);
        params.put("sign",sign);
        //请求
        String body = Convert.convert(JSONObject.class,params).toJSONString();
        String rbody = HttpUtil.post(url+method, body);
        if(StringUtils.isBlank(rbody)){
            throw new AppException("返回为空");
        }
        logger.info("金华行开卡返回："+rbody);
        JSONObject rbodyJson = null;
        try{
            rbodyJson = JSONObject.parseObject(rbody);
        }catch (Exception e){
            logger.error("金华行开卡返回数据异常",e);
            throw new AppException("金华行开卡失败");
        }
        if(rbodyJson.containsKey("code")){
            Integer code = rbodyJson.getInteger("code");
            if(code==0){//成功
                if(rbodyJson.containsKey("data")){
                    JSONObject data = rbodyJson.getJSONObject("data");
                    Map<String,Object> map = new HashMap<>();
                    map.put("vcardid",data.get("vcardid"));
                    map.put("userkey_public",data.get("userkey_public"));
                    return map;
                }
            }else {
                if(rbodyJson.containsKey("msg") && StringUtils.isNotBlank(rbodyJson.getString("msg"))){
                    throw new AppException("金华行接口返回错误:"+rbodyJson.getString("msg"));
                }else {
                    throw new AppException("金华行接口返回错误");
                }
            }
        }else {
            logger.error("金华行开卡返回数据异常,rbody:"+rbody);
            throw new AppException("金华行开卡失败");
        }
        return null;
    }

    /**
     * 注销金华行账号
     */
    private void cancelAccount(String vcardid){
        String method = "/ccard/account_cancel";
        Map<String,Object> params = new HashMap<>();
        params.put("vcardid",vcardid);
        //设置公共参数
        getCommonParams(params);
        //获取签名
        String sign = getSign(params,null);
        params.put("sign",sign);
        String body = Convert.convert(JSONObject.class,params).toJSONString();
        String rbody = HttpUtil.post(url+method, body);
        if(StringUtils.isBlank(rbody)){
            throw new AppException("返回为空");
        }
        logger.info("金华行注销卡返回："+rbody);
        JSONObject rbodyJson = null;
        try{
            rbodyJson = JSONObject.parseObject(rbody);
        }catch (Exception e){
            logger.error("金华行注销卡返回数据异常",e);
        }
        if(rbodyJson.containsKey("code")) {
            Integer code = rbodyJson.getInteger("code");
            if(code!=0){
                logger.error("金华行注销卡失败",rbodyJson.getString("msg"));
                throw new AppException(rbodyJson.getString("msg"));
            }
        }else{
            logger.error("金华行注销卡参数解析失败");
        }
    }

    private void getCommonParams(Map<String,Object> params){
        params.put("version","1.0");
        if(StringUtils.isBlank(appid)){
            throw new AppException("金华行appid参数(jhx_app_id)未配置");
        }
        params.put("appid",appid);
        Long timestamp = new Date().getTime()/1000;
        params.put("timestamp",timestamp);
        Integer nonce = (int)((Math.random()+1)*10000);
        params.put("nonce",nonce);
    }

    /**
     * 获取金华行接口签名
     * 1.除sign字段外，所有参数按照字段名的ASCII码从小到大排序后（字典序），使用URL键值对的格式（即Param1=value1&param2=value2…）拼接而成签名原始串，空值不参与签名组串；
     * 2.签名原始串中，字段名和字段值都采用原始值，不进行URL转义；
     * 3.得到的字符串进行MD5，并转换为大写；
     * @param params
     * @return
     */
    private String getSign(Map<String,Object> params,String appkey){
        Set<String> keys = params.keySet();
        List<String> keyList = new ArrayList<>(keys);
        Collections.sort(keyList);
        StringBuffer sb = new StringBuffer();
        for(String key : keyList){
            if(sb.length()>0){
                sb.append("&");
            }
            sb.append(key).append("=").append(params.get(key));
        }
        if(StringUtils.isNotBlank(appkey)){
            sb.append(appkey);
        }
        logger.info("签名原始串："+sb.toString());
        return StringUtils.upperCase(DigestUtils.md5DigestAsHex(sb.toString().getBytes()));
    }


    private BusTravelVcardidVO getBusTravelVcardidVO(BaseVO vo){
        BusTravelVcardidVO busTravelVcardidVO = null;
        String body = Convert.convert(JSONObject.class,vo).toJSONString();
        String rbody = HttpUtil.createPost(jhrcUrl+"/busTravel/getVcardid")
                .header("accessToken",vo.getAccessToken())
                .body(body).execute().body();
        if(StringUtils.isNotBlank(rbody)){
            try{
                JSONObject rbodyJson = JSONObject.parseObject(rbody);
                if("0".equals(rbodyJson.getString("code"))){
                    busTravelVcardidVO = Convert.convert(BusTravelVcardidVO.class,rbodyJson.getJSONObject("result"));
                }else {
                    throw new AppException(rbodyJson.getString("message"));
                }
            }catch (Exception e){
                logger.error("获取本地卡信息失败",e);
                throw new AppException("获取本地卡信息失败");
            }
        }else {
            throw new AppException("获取本地卡信息失败:返回未空");
        }
        return busTravelVcardidVO;
    }

    private void saveVcardid(BusTravelVcardidVO vo){
        String body = Convert.convert(JSONObject.class,vo).toJSONString();
        String rbody = HttpUtil.createPost(jhrcUrl+"/busTravel/saveVcardid")
                .header("accessToken",vo.getAccessToken())
                .body(body).execute().body();
        if(StringUtils.isNotBlank(rbody)){
            try{
                JSONObject rbodyJson = JSONObject.parseObject(rbody);
                if(!"0".equals(rbodyJson.getString("code"))){
                    throw new AppException(rbodyJson.getString("message"));
                }
            }catch (Exception e){
                logger.error("保存本地卡信息失败",e);
                throw new AppException("保存本地卡信息失败");
            }
        }else {
            throw new AppException("保存本地卡信息失败:返回未空");
        }
    }

}
